perm filename UDPSER.MAC[IP,SYS] blob
sn#746425 filedate 1984-03-21 generic text, type T, neo UTF8
title UDPSer
subttl provan
search f,s
search NetDef ; network definitions
search MacTen ; search only if symbol not found in NetDef
sall
$reloc
$high
XP VUDPSr,1 ; UDP version
comment \
this module contains the support routines for the User Datagram
protocol as defined in RFC-768.
\
subttl defintions describing a UDP leader
; see RFC-768 for details of this header.
UDPLen==:2 ; number of words in an UDP leader.
$low ; define the storage needed
UDPIBH: block NBHLen ; buffer header.
UDPIBf: block UDPLen ; words needed for header
; the following block is used to create a UDP leader for output.
; it is filled and then converted to 36 bit buffers all under ScnOff.
UDPObf: block NBHLen+UDPLen ; output buffer for forming leader
$high ; back to protected code
UDPPnt: point 8,UDPIBf ; pointer to start loading the
; header block from the stream.
; define the actual header fields. position is the bit position of the
; left most bit.
;
; name word position width
; UDP uses the standard ports, StdSP and StdDP.
;DefFd. UDPSP, 0, 0, 16 ; source port of message
;DefFd. UDPDP, 0, 16, 16 ; destination port
DefFd. UDPSiz, 1, 0, 16 ; length of packet
DefFd. UDPChk, 1, 16, 16 ; UDP checksum
subttl definitions
subttl process incoming UDP message
entry UDPIn ; only load this module if IP calls this routine
UDPIn::
move p2,MsgLen(f) ; get length of message through IP
ifn FtChck,< ; doing checksum
setz p3, ; clear checksum
move t1,p2 ; make sure to checksum length
; of UDP message before we
; convert it to length of segment.
pushj p,CSmHWd## ; checksum the length.
>
caige p2,UDPLen*4 ; cut length by that amount
jrst NoLead ; not enough message to read in leader
movei t1,UDPIBH ; get pointer to input leader
move t2,ABfLst(f) ; get last buffer so far
stor. t1,NBHNxt,(t2) ; make us their next
movem t1,ABfLst(f) ; and make us last (for grins)
move t1,UDPPnt ; point at the storage block
movei t2,UDPLen*4 ; length of leader in bytes
stor. t2,NBHCnt,UDPIBH ; store in buffer header
pushj p,GetLed## ; get the leader and checksum
jrst NoLead ; not enough bytes for leader.
load. t1,UDPSiz,UDPIBf ; get length from our packet
camle t1,p2 ; IP at least as big as we need?
jrst NoMess ; nope. forget it.
subi t1,UDPLen*4 ; cut length by amount of leader
movem t1,MsgLen(f) ; save length of UDP message
pushj p,GetMes## ; copy T1 bytes in.
jrst NoMess ; problem reading message
move p1,t1 ; save new stream pointer for later.
ifn FtChck,< ; doing checksumming
load. t1,UDPChk,UDPIBf ; get the checksum from the leader
jumpe t1,UDPNCk ; this guy doesn't do checksums
move t1,RmtAdr(f) ; get their address.
pushj p,CSmWrd## ; add in that checksum.
move t1,LclAdr(f) ; our address
pushj p,CSmWrd## ; checksum it.
move t1,Protcl(f) ; get the protocol
pushj p,CSmHWd## ; checksum that half a word
; bear in mind that the checksum we now have in P3 has, along with
; all the right stuff, its own one's complement. therefore, what
; we really have is <checksum> + -<checksum>, which is 0.
; further, since <checksum> has some bit on (otherwise the
; sender isn't checksuming and we wouldn't be here), it can be
; shown that the brand of one's complement 0 we must have is
; the version with all 1's. if that's what we have, we're ok.
; if not, the checksum failed.
hrrzs p3 ; get just the checksum
caie p3,<1←↑d16>-1 ; magic explained above
jrst BadChk ; checksum is bad.
UDPNCk: ; here to skip over the checksum checks because sender is not
; checksumming the messages.
>
aos UDPMsg## ; count another UDP message seen
move t1,RmtAdr(f) ; source (foreign host address)
load. t2,StdSP,TCPIBf ; get his port
movem t2,RmtPrt(f) ; and keep pseudo DDB up-to-date
load. t3,StdDP,TCPIBf ; get my port
movem t3,LclPrt(f) ; still keep pseudo DDB up-to-date
move t4,Protcl(f) ; get protocol
move p3,MsgLen(f) ; put length of this message
; somewhere where we can get
; it for the new DDB.
push p,f ; save current DDB, in case we fail
pushj p,FndDDB## ; scan network DDBs for the one
; that matches.
jrst NewCon ; this is one we haven't heard of
pop p,(p) ; don't want that F any more.
NewLst: ; return here if we are now listening
; for an unknown port (exec port).
movem p3,MsgLen(f) ; remember the message length
; in the new DDB.
pass packet to owner
subttl process a connection which has no DDB
; handle a connection to a port which is not listening.
; port number is in T3. old DDB (at this writing, always the pseudo
; DDB) is on the stack. it STAYS on the stack through most of
; this routine, so watch your ass or you'll try to popj p, to it.
NewCon:
; remember that we STILL have the old DDB on the stack.
; first check for a perpetual listen on that socket
movei t4,PlsLen-1 ; point at last entry
NewCo1: camn t3,PlsPrt(t4) ; is this it?
jrst PLsSn ; yes. a perptual listen seen.
sojge t4,NewCo1 ; count down
caxl t3,FrePrt ; is it below freely assigned ports?
jrst NotExc ; yes. not an exec port.
; now check for pemanent port services, handled through Telnet
skipe t1,t3 ; position our port number better
; (zero isn't legal)
PUSHJ P,WKPFND ;IS THIS SOCKET'S SERVICE IMPLEMENTED?
jrst NoPort ; remember this "error"
move t4,t1 ; save service offset
MOVEI J,0 ;NO JOB NUMBER YET
PUSHJ P,DDBGET## ;TRY FOR FREE DDB
jrst NoDDB ; can't get one
PUSHJ P,ITYGET## ;GET A PORT
jrst NoITY ; can't get one
MOVSI u,TTYKBD!TTYPTR
IORb u,TTYLIN(F) ; SET TTY BITS, get ITY's LDB into U
PUSHJ P,TSETBI## ;CLEAR INPUT BUFFER
PUSHJ P,TSETBO## ;CLEAR OUTPUT BUFFER
move t1,t4 ; position pointer to service.
HRRO T2,WKPSRV(T1) ;FETCH POINTER TO LOGICAL NAME
POP T2,DEVLOG(F) ;SET LOGICAL NAME INTO DDB
LDB T1,WKPTFC ;FETCH TTY FORCED COMMAND INDEX
pushj p,TTFORC## ;FORCE THE APPROPRIATE COMMAND
; here from perpetual listen setup
NowCon: pushj p,PrpDDB ; set essential DDB words
pop p,t2 ; get back the DDB which was used
; while the message was arriving.
;now fill in the information we know
move t1,RmtAdr(t2) ; get the foreign host address.
movem t1,RmtAdr(f) ; and save it the real DDB
move t1,NetAdr(t2) ; get ARPA address
movem t1,NetAdr(f) ; save in the DDB
move t1,RmtPrt(t2) ; get the source port (his port)
movem t1,RmtPrt(f) ; save in DDB
move t1,LclPrt(t2) ; get the destination port (my port)
movem t1,LclPrt(f) ; save in DDB
movei t1,S%List ; get state code "listen"
movem t1,State(f) ; make it this DDB's state
pushj p,NewLst ; go back a process this message
; as if nothing has happened.
move t2,State(f) ; now get the state
caie t2,S%List ; still listening?
popj p, ; no. just return.
pushj p,DDBFls## ; clear out DDB
pjrst DDBRel## ; and return it to free pool
; here to deal with a perpetual listen found
PLsSn: move j,PlsJob(t4) ; get job number listening
pushj p,DDBGet## ; get a DDB and assign it to this job.
jrst NoDDB ; can't. count and deny access
movei t1,PlsPID(t4) ; point at the PID to notify
hrrzi t2,DevNam(f) ; point at the device name in the
; DDB as the data to send.
hrli t2,1 ; just that one word, please.
setz j, ; mark as being sent from interupt
; level.
pushj p,SendSI## ; send the IPCF packet to the user
jrst NoIPCF ; oops. flush DDB and deny connection
jrst NowCon ; now process this packet
NotExc: pop p,f ; restore fake DDB.
movei u,TCPIBf ; point at TCP leader
move p3,TCPFlg(u) ; get the flags from leader.
jumpe p2,TryRst ; just reset if no options
hlrz t1,p2 ; get the first buffer of options
pushj p,RelBuf## ; free the options.
jrst TryRst ; try to send a reset and
; return the buffers and return.
;ROUTINE TO CHECK LEGALITY OF AN EXEC Well Known Port.
; MOVE t1,[local port NUMBER]
; PUSHJ P,WKPFND
; ERROR--SERVICE NOT IMPLEMENTED
; NORMAL--T1 CONTAINS INDEX INTO SERVER TABLE (WKPSRV)
WKPFND: pushj p,save2## ; get p1 and p2
move p2,t1 ; save port number
MOVSI t1,-WKPNUM ;NUMBER OF SERVICES IMPLEMENTED
WKPFN1: LDB p1,WKPSKT ;FETCH SOCKET NUMBER OF THIS SERVICE
CAMN p1,p2 ;MATCH?
JRST CPOPJ1 ;YES, GOOD RETURN, T1 is offset.
AOBJN t1,WKPFN1 ;NO, TRY NEXT
POPJ P, ;ERROR--SERVICE NOT IMPLEMENTED
;TABLE OF DEFINED SERVICES AVAILABLE THROUGH EXEC WKP.
; MACRO TO DEFINE A SERVICE:
; SERVER (PORT# , TTY FORCED COMMAND , LOGICAL NAME)
DEFINE SERVER(SKT,TFC,NAME) <
↑D<SKT>B26 + TFC## ,, [SIXBIT\NAME\]
>
WKPSRV:
;[tcp] SERVER (3,TTFCXF,FTPSRV) ;FILE TRANSFER PROTOCOL SERVER
SERVER (21,TTFCXF,FTPSRV) ;[tcp] FILE TRANSFER PROTOCOL SERVER
SERVER (23,TTFCXH,NETUSR) ;TELNET SERVER
server (79,ttfcxg,FngSrv) ;(241) finger service
IFN FTPATT,<
0 ;SPACE TO PATCH IN NEW SERVICES
0
>
WKPNUM==.-WKPSRV ;NUMBER OF DEFINED SERVICES
WKPSKT: POINT 9,WKPSRV(T1),8 ;POINTER TO SERVICE SOCKET NUMBER
WKPTFC: POINT 9,WKPSRV(T1),17 ;POINTER TO TTY FORCED COMMAND INDEX
subttl returns
; message ended before leader was read in
NoLead: aos UDELed## ; error with leader
popj p, ; return
; bytes ended before message or ran out of buffers while reading it
NoMess: aos UDEMes## ; count error reading message in
popj p,
BadChk: aos UDEChk## ; checksum wrong. count it
pjrst BufFls ; flush out buffers and return
NoPort: aosa TCEPrt## ; incoming to a exec port we
; don't watch.
NoDDB: aos TCEDDB## ; couldn't get DDB when needed.
BadCon: pop p,f ; restore fake DDB with info in it.
scnoff ; stop interupts
pushj p,SndNSP## ; call ICMP to tell him we
; don't do that.
scnon ; interrupts ok again.
jrst BufFls ; go flush message and options
NoIPCF: aosa TCEIPC## ; IPCF failed
NoITY: aos TCEITY## ; couldn't get an ITY when i
; wanted one.
pushj p,DDBREL## ; RETURN THE DDB
jrst BadCon ; do bad connection things
; subroutine to release all the buffers in our message.
BufFls: hlrz t1,p1 ; get first buffer of chain.
pjrst RelBuf## ; release the entire chain.
v subttl UDPMak
;++
; Functional description:
;
; put UDP leader (in 32 bit format) into fixed UDP output leader
; buffer. then link the buffer to the beginning of the
; current output stream. then send the message down to the
; next level of protocol for further processing.
;
;
; Calling sequence:
;
; move f,DDB
; pushj p,UDPMak
; <always returns here>
;
; Input parameters:
;
; f - DDB for connection
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; data in DDB
v;
; Implicit outputs:
;
; data in DDB
;
; Routine value:
;
; returns non-skip if can't get a buffer
;
; Side effects:
;
; adds a buffer to the beginning of the current output stream.
;--
UDPMak::
movei t1,UDPOBf ; point at the output leader space
exch t1,OBfFst(f) ; make us first, get old first
stor. t1,NBHNxt,UDPOBf ; link old first to us.
move t1,RmtPrt(f) ; get his port
stor. t1,StdDP,NBHLen+UDPOBf ; that's the destination port
move t1,LclPrt(f) ; get my port
stor. t1,StdSP,NBHLen+UDPOBf ; that's the source port
movei t1,UDPLen*4 ; get length in bytes
stor. t1,NBHCnt,UDPOBf ; save byte count for this buffer
addb t1,OBfByt(f) ; get a grand total in bytes.
stor. t1,UDPSiz,NBHLen+UDPOBf ; save in length word.
; one would add OPTIONS around here somewhere.
ifn FtChck,< ; doing checksums?
move t1,[point 16,NBHLen+UDPOBf]; starting pointer
movei t2,UDPLen*4 ; get length in bytes of leader
pushj p,CSmWds## ; and checksum it.
move t1,RmtAdr(f) ; get remote address
pushj p,CSmWrd## ; add it to checksum
move t1,LclAdr(f) ; local address, too
pushj p,CSmWrd## ; add it in.
move t1,Protcl(f) ; and get protocol
pushj p,CSmHWd## ; and add it in as well
move t1,OBfByt(f) ; get byte count of message
; plus leader
pushj p,CSmHWd## ; add that to checksum, too.
txc p3,msk.hw ; send one's complement of the sum
txnn p3,msk.hw ; if zero, make it...
movei p3,msk.hw ; ...the zero with all bits on
stor. p3,UDPChk,NBHLen+UDPOBf ; save the checksum in the leader.
>
ife FtChck,< ; not doing checksums
zero. t1,UDPChk,NBHLen+UDPOBf ; flag that we aren't checksumming
>
pjrst IpMake## ; call next level of protocol
subttl UDPChk
;++
; Functional description:
;
; subroutine to do various once a second checks to an IMP DDB.
;
;
; Calling sequence:
;
; move f,DDB
; pushj p,UDPChk##
; <always returns here>
;
; Input parameters:
;
; f - DDB of an IMP device.
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; DDB and queues
;
; Implicit outputs:
;
; DDB and queues
;
; Routine value:
;
; none.
;
; Side effects:
;
; may didle with output queues if it finds it needs to retransmit.
; may delete DDB altogether, although DevSer will still have the
; link to the next DDB. (HINT: call this after doing everything else.)
;--
UDPChk::
should need this
subttl TcpRst
;++
; Functional description:
;
; subroutine to do various things for a job that just did
; a RESET UUO.
;
;
; Calling sequence:
;
; move j,<job number>
; pushj p,TCPRst
; <always returns here>
;
; Input parameters:
;
; j - job number reseting
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; perpetual listen tables.
;
; Implicit outputs:
;
; perpetual listen tables.
;
; Routine value:
;
; none.
;
; Side effects:
;
; will clear out the PID for any entry set last by this job.
;--
TCPRst::
movei t1,PlsLen-1 ; point at last entry in tables
TCPRs1: camn j,PlsJob(t1) ; is this me?
setzm PlsPID(t1) ; yes. clear it by clearing the PID
sojge t1,TCPRs1 ; try the next.
popj p, ; all done.
$high
$LIT
END